package cn.rhzz.restore;

import cn.rhzz.restore.HttpUtils;
import cn.rhzz.restore.DateUtil;
import okhttp3.OkHttpClient;
import cn.rhzz.restore.ConfigFile;
import cn.rhzz.restore.StatusFile;
import cn.rhzz.restore.Constants;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.*;
import java.io.File;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.commons.io.FileUtils;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class Main {

	private static final String CONFIG_FILENAME = "config.json";
	private static final String STATUS_FILENAME = "status.txt";
	private static final Logger logger = LoggerFactory.getLogger(Main.class);

	public static void login(HttpUtils httpUtil, String baseUrl, String username, String password) throws Exception {
		String userLoginResponse = null;
		try {
			// 用户登录，自动维护Cookie
			userLoginResponse = httpUtil.post(baseUrl + Constants.API_LOGIN,
					httpUtil.getUserLoginBody(username, password));
		} catch (IOException e1) {
			logger.error("login failure: " + e1.getMessage());
			throw new Exception("Fail to login: " + e1.getMessage());
		}

		JSONObject userLoginResponseJson = new JSONObject(userLoginResponse);
		String userLoginStatus = userLoginResponseJson.getString("result");

		if (userLoginStatus == "error") {
			logger.error("login failure: " + username);
			throw new Exception("Error to login: " + userLoginResponse);
		}
	}

	public static List<JSONObject> getAllRecords(HttpUtils httpUtil, String baseUrl, List<Integer> oldFileIds) {
		int curPageInt = 1; // 获取第一页记录，后续自增来获取剩下页的记录，直到最后一页，该变量改回"1"为下一次做准备
		int totalPage = 0; // 获取此次的总页数
		boolean running = true;
		List<JSONObject> recordList = new ArrayList<JSONObject>();// 保存文件记录
		while (running) { // 获取此次所有还原文件记录

			// 获取还原文件记录
			String curPageString = String.valueOf(curPageInt);
			String onePage = null;
			try {
				onePage = httpUtil.get(
						httpUtil.getFileListBody(baseUrl + Constants.API_FILELIST, "srcip", "", curPageString, "50"));
			} catch (IOException e) {
				logger.error("Failed to get file records: " + e.getMessage());
			}

			JSONObject fileList = new JSONObject(onePage);
			JSONObject detail = fileList.getJSONObject("detail");
			totalPage = detail.getInt("total_page");
			JSONArray fileRecords = detail.getJSONArray("files");
			for (int i = 0; i < fileRecords.length(); i++) {
				JSONObject fileRecord = fileRecords.getJSONObject(i);
				int fileId = fileRecord.getInt("file_id");

				if (oldFileIds != null && oldFileIds.contains(fileId)) {
					continue;
				}
				recordList.add(fileRecord);
			}
			curPageInt++;
			if (curPageInt > totalPage) {
				running = false;
			}
		}
		return recordList;
	}

	public static List<Integer> downloadFiles(HttpUtils httpUtil, String baseUrl, List<JSONObject> recordList,
			String downloadPath) {
		int totalCount = 0; // 每次下载数量，写到日志里
		int successCount = 0;
		List<Integer> fileIds = new ArrayList<>();
		for (JSONObject fileJson : recordList) {
			String fileName = fileJson.getString("filename");
			if (fileName == null || "".equals(fileName.trim())) {
				continue;
			}
			int fileIdInt = fileJson.getInt("file_id");

			String fileIdString = String.valueOf(fileIdInt);
			fileName = fileIdInt + "_" + fileName.replaceAll("/", "_").replaceAll(":", "_").replaceAll("\\\\", "_").replaceAll("\\*", "_").replaceAll("\\?", "_").replaceAll("\"", "_").replaceAll("<", "_").replaceAll(">", "_").replaceAll("\\|", "_");
			String curYearMonth = "/" + DateUtil.getCurYear() + DateUtil.getCurMonth();
			try {
				httpUtil.downloadFile(httpUtil.getDownloadFileBody(baseUrl + Constants.API_FILEDOWNLOAD, fileIdString),
						downloadPath + curYearMonth, fileName);
				fileIds.add(fileIdInt);
				logger.info("Success to download file: " + fileName);
				successCount++;
			} catch (Exception e) {
				logger.error("Error download file: " + e.getMessage());
			}
			totalCount++;
		}

		logger.info("Total " + totalCount + " files need download, success download " + successCount + " files");
		return fileIds;
	}

	public static List<Integer> getCacheDownloadFileIds(String statusFile) throws Exception {
		List<Integer> oldFileIds = new ArrayList<>();
		try {
			String statusStr = StatusFile.getStatusFile(statusFile); // 状态维持的是记录ID不是时间
			if (statusStr != null && !"".equals(statusStr)) {
				String[] statusArray = statusStr.split(",");
				for (String x : statusArray) {
					oldFileIds.add(Integer.parseInt(x));
				}

			}
		} catch (IOException e2) {
			logger.error("Failed to read status file: " + e2.getMessage());
			throw new Exception(e2);
		}
		return oldFileIds;
	}

	public static void writeFileIds2File(List<Integer> fileIds, String statusFile) {
		try {
			if (fileIds != null && fileIds.size() > 0) {
				StringBuilder cacheData = new StringBuilder();
				cacheData.append(fileIds.get(0));
				for (int i = 1; i < fileIds.size(); i++) {
					cacheData.append(",").append(fileIds.get(i));
				}

				StatusFile.setStatusFile(statusFile, cacheData.toString());
			}
		} catch (IOException e1) {
			logger.error("Erro write to status file: " + e1.getMessage());
		}
	}

	public static void main(String[] args) {
		String givenConfig = null;
		String basePath = null;
		if (args != null && args.length >= 2) {
			givenConfig = args[1];
		} else {
			// 配置文件放在项目目录下, .../download_restore_file/config.json;
			basePath = Main.class.getResource("/").getPath();
			givenConfig = basePath + CONFIG_FILENAME;
		}
		logger.info("The path where the configuration file resides: " + basePath);
		ConfigFile conf = null;
		try {
			conf = new ConfigFile(givenConfig);
		} catch (IOException e1) {
			logger.error("读取配置文件失败: " + e1.getMessage());
		} // 获取配置文件参数
		String baseUrl = conf.getValue("url"); // 获取服务器IP地址
		String username = conf.getValue("username"); // 获取登录用户名
		String password = conf.getValue("password"); // 获取登录密码
		String downloadPath = conf.getValue("download_path"); // 获取文件下载目的地路径
		int check_interval = conf.getIntValue("check_interval"); // 获取扫描间隔时间

		HttpUtils httpUtil = new HttpUtils(); // 创建请求发起工具对象
		String statusFile = basePath + STATUS_FILENAME;

		while (true) {
			try {
				List<Integer> oldFileIds = getCacheDownloadFileIds(statusFile);

				login(httpUtil, baseUrl, username, password);

				List<JSONObject> records = getAllRecords(httpUtil, baseUrl, oldFileIds);

				List<Integer> downloadFileIds = downloadFiles(httpUtil, baseUrl, records, downloadPath);

				oldFileIds.addAll(downloadFileIds);
				writeFileIds2File(oldFileIds, statusFile);

			} catch (Exception e) {
				logger.error("Error in main loop: " + e.getMessage());
			} finally {
				try {
					Thread.sleep(check_interval);
				} catch (InterruptedException ex) {
					logger.error("Error sleep: " + ex.getMessage());
				}

			}
		}

	}
}
